home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / AppInstall / widgets / ReleaseNotesViewer.py < prev    next >
Encoding:
Python Source  |  2009-03-31  |  7.5 KB  |  192 lines

  1. # ReleaseNotesViewer.py
  2. #  
  3. #  Copyright (c) 2006 Sebastian Heinlein
  4. #  
  5. #  Author: Sebastian Heinlein <sebastian.heinlein@web.de>
  6. #
  7. #  This modul provides an inheritance of the gtk.TextView that is 
  8. #  aware of http URLs and allows to open them in a browser.
  9. #  It is based on the pygtk-demo "hypertext".
  10. #  This program is free software; you can redistribute it and/or 
  11. #  modify it under the terms of the GNU General Public License as 
  12. #  published by the Free Software Foundation; either version 2 of the
  13. #  License, or (at your option) any later version.
  14. #  This program is distributed in the hope that it will be useful,
  15. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. #  GNU General Public License for more details.
  18. #  You should have received a copy of the GNU General Public License
  19. #  along with this program; if not, write to the Free Software
  20. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. #  USA
  22.  
  23.  
  24. import pygtk
  25. import gtk
  26. import pango
  27. import subprocess
  28. import os
  29.  
  30. class ReleaseNotesViewer(gtk.TextView):
  31.     def __init__(self, notes=None):
  32.         """Init the ReleaseNotesViewer as an Inheritance of the gtk.TextView.
  33.            Load the notes into the buffer and make links clickable"""
  34.         # init the parent
  35.         gtk.TextView.__init__(self)
  36.         # global hovering over link state
  37.         self.hovering = False
  38.         self.first = True
  39.         # setup the buffer and signals
  40.         self.set_property("editable", False)
  41.         self.set_cursor_visible(False)
  42.         self.buffer = gtk.TextBuffer()
  43.         self.set_buffer(self.buffer)
  44.         self.connect("event-after", self.event_after)
  45.         self.connect("motion-notify-event", self.motion_notify_event)
  46.         self.connect("visibility-notify-event", self.visibility_notify_event)
  47.         #self.buffer.connect("changed", self.search_links)
  48.         self.buffer.connect_after("insert-text", self.on_insert_text)
  49.         # search for links in the notes and make them clickable
  50.         if notes != None:
  51.             self.buffer.set_text(notes)
  52.  
  53.     def tag_link(self, start, end, url):
  54.         """Apply the tag that marks links to the specified buffer selection"""
  55.         tag = self.buffer.create_tag(None, foreground="blue",
  56.                                      underline=pango.UNDERLINE_SINGLE)
  57.         tag.set_data("url", url)
  58.         self.buffer.apply_tag(tag , start, end)
  59.  
  60.     def on_insert_text(self, buffer, iter_end, text, *args):
  61.         """Search for http URLs in newly inserted text  
  62.            and tag them accordingly"""
  63.         iter = buffer.get_iter_at_offset(iter_end.get_offset() - len(text))
  64.         iter_real_end = buffer.get_end_iter()
  65.         for protocol in ["http://", "https://"]:
  66.             while True:
  67.                 # search for the next URL in the buffer
  68.                 ret = iter.forward_search(protocol, 
  69.                                       gtk.TEXT_SEARCH_VISIBLE_ONLY,
  70.                                       iter_end)
  71.                 # if we reach the end break the loop
  72.                 if not ret:
  73.                     break
  74.                 # get the position of the protocol prefix
  75.                 (match_start, match_end) = ret
  76.                 match_tmp = match_end.copy()
  77.                 while True:
  78.                     # extend the selection to the complete URL
  79.                     if match_tmp.forward_char():
  80.                         text =  match_end.get_text(match_tmp)
  81.                         if text in (" ", ")", "]", "\n", "\t",">","!"):
  82.                             break
  83.                     else:
  84.                         break
  85.                     match_end = match_tmp.copy()
  86.                 # call the tagging method for the complete URL
  87.                 url = match_start.get_text(match_end)
  88.                 tags = match_start.get_tags()
  89.                 tagged = False
  90.                 for tag in tags:
  91.                     url = tag.get_data("url")
  92.                     if url != "":
  93.                         tagged = True
  94.                         break
  95.                 if tagged == False:
  96.                     self.tag_link(match_start, match_end, url)
  97.                 # set the starting point for the next search
  98.                 iter = match_end
  99.  
  100.     def event_after(self, text_view, event):
  101.         """callback for mouse click events"""
  102.         # we only react on left mouse clicks
  103.         if event.type != gtk.gdk.BUTTON_RELEASE:
  104.             return False
  105.         if event.button != 1:
  106.             return False
  107.  
  108.         # try to get a selection
  109.         try:
  110.             (start, end) = self.buffer.get_selection_bounds()
  111.         except ValueError:
  112.             pass
  113.         else:
  114.             if start.get_offset() != end.get_offset():
  115.                 return False
  116.  
  117.         # get the iter at the mouse position
  118.         (x, y) = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
  119.                                               int(event.x), int(event.y))
  120.         iter = self.get_iter_at_location(x, y)
  121.         
  122.         # call open_url if an URL is assigned to the iter
  123.         tags = iter.get_tags()
  124.         for tag in tags:
  125.             url = tag.get_data("url")
  126.             if url != None:
  127.                 self.open_url(url)
  128.                 break
  129.  
  130.     def open_url(self, url):
  131.         """Open the specified URL in a browser"""
  132.         # Find an appropiate browser
  133.         if os.path.exists('/usr/bin/gnome-open'):
  134.             command = ['gnome-open', url]
  135.         else:
  136.             command = ['x-www-browser', url]
  137.  
  138.         # Avoid to run the browser as user root
  139.         if os.getuid() == 0 and os.environ.has_key('SUDO_USER'):
  140.             command = ['sudo', '-u', os.environ['SUDO_USER']] + command
  141.  
  142.         subprocess.Popen(command)
  143.  
  144.     def motion_notify_event(self, text_view, event):
  145.         """callback for the mouse movement event, that calls the
  146.            check_hovering method with the mouse postition coordiantes"""
  147.         x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
  148.                                                  int(event.x), int(event.y))
  149.         self.check_hovering(x, y)
  150.         self.window.get_pointer()
  151.         return False
  152.     
  153.     def visibility_notify_event(self, text_view, event):
  154.         """callback if the widgets gets visible (e.g. moves to the foreground)
  155.            that calls the check_hovering method with the mouse position
  156.            coordinates"""
  157.         (wx, wy, mod) = text_view.window.get_pointer()
  158.         (bx, by) = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx,
  159.                                                      wy)
  160.         self.check_hovering(bx, by)
  161.         return False
  162.  
  163.     def check_hovering(self, x, y):
  164.         """Check if the mouse is above a tagged link and if yes show
  165.            a hand cursor"""
  166.         _hovering = False
  167.         # get the iter at the mouse position
  168.         iter = self.get_iter_at_location(x, y)
  169.         
  170.         # set _hovering if the iter has the tag "url"
  171.         tags = iter.get_tags()
  172.         for tag in tags:
  173.             url = tag.get_data("url")
  174.             if url != None:
  175.                 _hovering = True
  176.                 break
  177.  
  178.         # change the global hovering state
  179.         if _hovering != self.hovering or self.first == True:
  180.             self.first = False
  181.             self.hovering = _hovering
  182.             # Set the appropriate cursur icon
  183.             if self.hovering:
  184.                 self.get_window(gtk.TEXT_WINDOW_TEXT).\
  185.                         set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
  186.             else:
  187.                 self.get_window(gtk.TEXT_WINDOW_TEXT).\
  188.                         set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
  189.